unit ecstringiser;
{ < This unit contains routines for turning event commands into their display
  in the event content's lists. }

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, fpjson, database, moveroutestringizer, Graphics, constants;

type
  TEcColour = (ecDefault, ecString, ecCode, ecFaded, ecInvisible,
  ecMessage, ecProgression, ecFlow, ecComment, ecParty, ecActor,
  ecMove, ecChar, ecPic, ecWait, ecScreen, ecAudioVideo,
  ecScene, ecSystem, ecMap, ecBattle, ecAdvanced);

  TEcPhrasePart = record
    Text: String;
    Colour: TEcColour;
  end;

  TEcPhrase = array of TEcPhrasePart;

  { TEcStringiser }

  TEcStringiser = class
    private
      FDb: TDatabase;
      MoveRouteStringiser: TMoveRouteStringizer;

      procedure SetDb(ADb: TDatabase);
      function OnOffCommand(Params: TJSONArray; OnStr, OffStr: String; Colour: TEcColour): TEcPhrase;
      function AddWait(Params: TJSONArray; WaitNumber: Integer; Phrase: TEcPhrase): TEcPhrase;
      function FileOrNone(Filename: String): String;
      function SoundDetails(Snd: TJSONObject): String;

      function Unknown(Code: Integer): TEcPhrase;
      function FormatTimerTime(TotalSecs: Integer): String;
      function CurrencyName: String;
      function Direction(DirCode: Integer): String;
      function Vehicle(Code: Integer): String;
      function TroopMemberName(MemberIndex: Integer): String;

      {Page 1}
      function ShowMessageStart(Params: TJSONArray): TEcPhrase;
      function ShowMessageLine(Params: TJSONArray): TEcPhrase;
      function ShowChoicesStart(Params: TJSONArray): TEcPhrase;
      function ShowChoicesBranch(Params: TJSONArray): TEcPhrase;
      function InputNumber(Params: TJSONArray): TEcPhrase;
      function SelectItem(Params: TJSONArray): TEcPhrase;
      function ScrollingTextStart(Params: TJSONArray): TEcPhrase;
      function ScrollingTextLine(Params: TJSONArray): TEcPhrase;

      function SetSwitches(Params: TJSONArray): TEcPhrase;
      function SetVariables(Params: TJSONArray): TEcPhrase;
      function SetSelfSwitch(Params: TJSONArray): TEcPhrase;
      function ControlTimer(Params: TJSONArray): TEcPhrase;
      function ConditionalBranch(Params: TJSONArray): TEcPhrase;
      function LabelEc(Params: TJSONArray): TEcPhrase;
      function GotoEc(Params: TJSONArray): TEcPhrase;
      function CallCommonEvent(Params: TJSONArray): TEcPhrase;
      function Comment(Params: TJSONArray): TEcPhrase;
      function CommentContinuation(Params: TJSONArray): TEcPhrase;

      function ChangeGold(Params: TJSONArray): TEcPhrase;
      function ChangeItemsWeaponsArmours_GetAction(Params: TJSONArray; ItemName: String): String;
      function ChangeWeaponsArmours_AddIncludingEquipment(Phrase: TEcPhrase; Params: TJSONArray): TEcPhrase;
      function ChangeItems(Params: TJSONArray): TEcPhrase;
      function ChangeWeapons(Params: TJSONArray): TEcPhrase;
      function ChangeArmours(Params: TJSONArray): TEcPhrase;
      function ChangeParty(Params: TJSONArray): TEcPhrase;

      function ActorEcs_GetActor(Params: TJSONArray): String;
      function ChangeHp_AddAllowKnockout(Phrase: TEcPhrase; Params: TJSONArray): TEcPhrase;
      function ChangeHpMpTp(Params: TJSONArray; EcName, PointName: String; HasKnockout: Boolean): TEcPhrase;
      function ChangeState(Params: TJSONArray): TEcPhrase;
      function CompleteRecovery(Params: TJSONArray): TEcPhrase;
      function ChangeExpLevel(Params: TJSONArray; IsLevel: Boolean): TEcPhrase;
      function ChangeParam(Params: TJSONArray): TEcPhrase;
      function ChangeSkill(Params: TJSONArray): TEcPhrase;
      function ChangeEquipment(Params: TJSONArray): TEcPhrase;
      function ChangeName(Params: TJSONArray): TEcPhrase;
      function ChangeClass(Params: TJSONArray): TEcPhrase;
      function ChangeNickname(Params: TJSONArray): TEcPhrase;
      function ChangeProfile(Params: TJSONArray): TEcPhrase;

      {Page 2}
      function TransferPlayer(Params: TJSONArray): TEcPhrase;
      function SetVehicleLocation(Params: TJSONArray): TEcPhrase;
      function SetEventLocation(Params: TJSONArray): TEcPhrase;
      function ScrollMap(Params: TJSONArray): TEcPhrase;
      function SetMoveRoute(Params: TJSONArray): TEcPhrase;
      function SetMoveRouteLine(Params: TJSONArray): TEcPhrase;
      function ShowAnimation(Params: TJSONArray): TEcPhrase;
      function ShowEmotionBalloon(Params: TJSONArray): TEcPhrase;

      function ShowMovePicture_Params(Params: TJSONArray): String;
      function ShowPicture(Params: TJSONArray): TEcPhrase;
      function MovePicture(Params: TJSONArray): TEcPhrase;
      function RotatePicture(Params: TJSONArray): TEcPhrase;
      function TintPicture(Params: TJSONArray): TEcPhrase;
      function ErasePicture(Params: TJSONArray): TEcPhrase;
      function Wait(Params: TJSONArray): TEcPhrase;
      function TintFlashScreen(Params: TJSONArray; FormatString: String): TEcPhrase;
      function ShakeScreen(Params: TJSONArray): TEcPhrase;
      function SetWeatherEffect(Params: TJSONArray): TEcPhrase;
      function Sound(Params: TJSONArray; CommandName: String; Colour: TEcColour): TEcPhrase;
      function FadeoutSound(Params: TJSONArray; CommandName: String): TEcPhrase;
      function PlayMovie(Params: TJSONArray): TEcPhrase;

      function BattleProcessing(Params: TJSONArray): TEcPhrase;
      function ShopProcessing(Params: TJSONArray; IsContinuation: Boolean): TEcPhrase;
      function NameInputProcessing(Params: TJSONArray): TEcPhrase;

      function ChangeVehicleBgm(Params: TJSONArray): TEcPhrase;
      function ChangeWindowColour(Params: TJSONArray): TEcPhrase;
      function ChangeActorImages(Params: TJSONArray): TEcPhrase;
      function ChangeVehicleImage(Params: TJSONArray): TEcPhrase;

      function ChangeTileset(Params: TJSONArray): TEcPhrase;
      function ChangeBattleBack(Params: TJSONArray): TEcPhrase;
      function ChangeParallax(Params: TJSONArray): TEcPhrase;
      function GetLocationInfo(Params: TJSONArray): TEcPhrase;
      function ChangeEnemyHpMpTp(Params: TJSONArray; EcName, PointName: String;
        HasKnockout: Boolean): TEcPhrase;
      function ChangeEnemyState(Params: TJSONArray): TEcPhrase;
      function EnemyCompleteRecoveryAppear(Params: TJSONArray; CommandName: String): TEcPhrase;
      function EnemyTranform(Params: TJSONArray): TEcPhrase;
      function ShowBattleAnimation(Params: TJSONArray): TEcPhrase;
      function ForceAction(Params: TJSONArray): TEcPhrase;
      function Script(Params: TJSONArray): TEcPhrase;
      function ScriptLine(Params: TJSONArray): TEcPhrase;
      function PluginCommand(Params: TJSONArray): TEcPhrase;
    public
      Troop: TJSONObject;

      constructor Create;
      destructor Destroy; override;
      property Db: TDatabase read FDb write SetDb;
      function StringiseEc(Command: TJSONObject): TEcPhrase;
  end;

function EcPPart(Text: String; Colour: TEcColour): TEcPhrasePart; inline;
function SimpleEcPhrase(Text: String; Colour: TEcColour): TEcPhrase; inline;
function EcIsContinuation(Code: Integer): Boolean;

implementation

uses
  database_items, globals, namehelper;

function EcPPart(Text: String; Colour: TEcColour): TEcPhrasePart; inline;
begin
  EcPPart.Text := Text;
  EcPPart.Colour := Colour;
end;

constructor TEcStringiser.Create;
begin
  Self.MoveRouteStringiser := TMoveRouteStringizer.Create;
end;

destructor TEcStringiser.Destroy;
begin
  MoveRouteStringiser.Free;
  inherited Destroy;
end;

procedure TEcStringiser.SetDb(ADb: TDatabase);
begin
  FDb := ADb;
  Self.MoveRouteStringiser.Db := ADb;
end;

function TEcStringiser.OnOffCommand(Params: TJSONArray; OnStr, OffStr: String;
  Colour: TEcColour): TEcPhrase;
var
  Str: String;
begin
  if Params.Integers[0] = 0 then
    Str := OffStr
  else
    Str := OnStr;

  OnOffCommand := TEcPhrase.Create(
    EcPPart(Str, Colour)
  );
end;

function TEcStringiser.AddWait(Params: TJSONArray; WaitNumber: Integer;
  Phrase: TEcPhrase): TEcPhrase;
var
  OldLength: Integer;
begin
  OldLength := Length(Phrase);
  if Params.Booleans[WaitNumber] = True then begin
    SetLength(Phrase, OldLength + 2);
    Phrase[OldLength] := EcPPart(rsSpace, ecFaded);
    Phrase[OldLength + 1] := EcPPart(rsFadedWait, ecFaded);
  end;

  Result := Phrase;
end;

function TEcStringiser.FileOrNone(Filename: String): String;
begin
  if Filename <> '' then
    FileOrNone := Filename
  else
    FileOrNone := rsNoFile;
end;

function TEcStringiser.SoundDetails(Snd: TJSONObject): String;
var
  Name: String = '';
  NameJson: TJSONString;
  Volume: Integer = 0;
  Pitch: Integer = 0;
  Pan: Integer = 0;
  NumberJson: TJSONNumber;
begin
  if (Snd <> nil) and Snd.Find('name', NameJson) then
    Name := NameJson.AsString;
  if (Snd <> nil) and Snd.Find('volume', NumberJson) then
    Volume := NumberJson.AsInteger;
  if (Snd <> nil) and Snd.Find('pitch', NumberJson) then
    Pitch := NumberJson.AsInteger;
  if (Snd <> nil) and Snd.Find('pan', NumberJson) then
    Pan := NumberJson.AsInteger;

  if Name <> '' then
    SoundDetails := rsSound.Format([Name, Volume, Pitch, Pan])
  else
    SoundDetails := rsNoFile;
end;

function TEcStringiser.Unknown(Code: Integer): TEcPhrase;
var
  Res: TEcPhrase;
begin
  SetLength(Res, 3);
  Res[0] := EcPPart(rsUnknownEc, ecDefault);
  Res[1] := EcPPart(rsSpace, ecDefault);
  Res[2] := EcPPart(rsCode.Format([Code]), ecFaded);

  Unknown := Res;
end;

function TEcStringiser.ShowMessageStart(Params: TJSONArray): TEcPhrase;
  function FormatFace: String;
  begin
    if Params.Strings[0] = '' then
      FormatFace := rsShowMessageNoFace
    else
      FormatFace := rsShowMessageFace.Format([
        Params.Strings[0],
        Params.Integers[1]
      ]);
  end;

begin
  ShowMessageStart := TEcPhrase.Create(
    EcPPart(rsShowMessageEc, ecMessage),
    EcPPart(rsColon, ecMessage),
    EcPPart(FormatFace, ecFaded),
    EcPPart(rsComma, ecFaded),
    EcPPart(GetMessageBgTypeName(Params.Integers[2]), ecFaded),
    EcPPart(rsComma, ecFaded),
    EcPPart(GetMessagePosName(Params.Integers[3]), ecFaded)
  );
end;

function TEcStringiser.ShowMessageLine(Params: TJSONArray): TEcPhrase;
begin
  ShowMessageLine := TEcPhrase.Create(
    EcPPart(rsShowMessageEc, ecInvisible),
    EcPPart(rsColon, ecMessage),
    EcPPart(Params.Strings[0], ecString)
  );
end;

function TEcStringiser.ShowChoicesStart(Params: TJSONArray): TEcPhrase;
  function FormatChoices(Choices: TJSONArray): String;
  var
    Res: String;
    I: Integer;
  begin
    Res := '';
    for I := 0 to Choices.Count -1 do begin
      if I <> 0 then
        Res := Res + rsComma + Choices[I].AsString
      else
        Res := Res + Choices[0].AsString
    end;

    FormatChoices := Res;
  end;

  function FormatPos: String;
  begin
    case Params.Integers[3] of
      0: FormatPos := rsLeft;
      1: FormatPos := rsHorzMiddle;
      2: FormatPos := rsRight;
    else
      FormatPos := rsUnknownParameter
    end;
  end;

  function FormatBranchNumber(Index: Integer): String;
  begin
    if Index < 0 then
      FormatBranchNumber := rsNotApplicable
    else
      FormatBranchNumber := rsNumber.Format([Index + 1]);
  end;

begin
  ShowChoicesStart := TEcPhrase.Create(
    EcPPart(rsShowChoicesEc, ecMessage),
    EcPPart(rsColon, ecMessage),
    EcPPart(FormatChoices(Params.Arrays[0]), ecString),

    EcPPart(rsSpace, ecDefault),

    EcPPart(rsOpenBracket, ecFaded),
      EcPPart(GetMessageBgTypeName(Params.Integers[4]), ecFaded),
      EcPPart(rsComma, ecFaded),
      EcPPart(FormatPos, ecFaded),
      EcPPart(rsComma, ecFaded),
      EcPPart(FormatBranchNumber(Params.Integers[2]), ecFaded),
      EcPPart(rsComma, ecFaded),
      EcPPart(FormatBranchNumber(Params.Integers[1]), ecFaded),
    EcPPart(rsCloseBracket, ecFaded)
  );
end;

function TEcStringiser.ShowChoicesBranch(Params: TJSONArray): TEcPhrase;
begin
  ShowChoicesBranch := TEcPhrase.Create(
    EcPPart(rsShowChoicesWhenEc, ecMessage),
    EcPPart(rsSpace, ecMessage),
    EcPPart(Params.Strings[1], ecString)
  );
end;

function TEcStringiser.InputNumber(Params: TJSONArray): TEcPhrase;
begin
  InputNumber := TEcPhrase.Create(
    EcPPart(rsInputNumberEc, ecMessage),
    EcPPart(rsColon, ecMessage),
    EcPPart(Db.GetVariableName(Params.Integers[0]), ecMessage),
    EcPPart(rsComma, ecMessage),
    EcPPart(rsInputNumberEc_digits.Format([Params.Integers[1]]), ecMessage)
  );
end;

function TEcStringiser.SelectItem(Params: TJSONArray): TEcPhrase;
begin
  SelectItem := TEcPhrase.Create(
    EcPPart(rsSelectItem, ecMessage),
    EcPPart(rsColon, ecMessage),
    EcPPart(Db.GetVariableName(Params.Integers[0]), ecMessage),
    EcPPart(rsComma, ecMessage),
    EcPPart(GetItemTypeName(Params.Integers[1]), ecMessage)
  );
end;

function TEcStringiser.ScrollingTextStart(Params: TJSONArray): TEcPhrase;
  function GetSettings: String;
  var
    Res: String;
  begin
    Res := rsScrollingText_speed.Format([Params.Integers[0]]);
    if Params.Booleans[1] then
      Res := Res + rsComma + rsScrollingText_noFastForward;
    GetSettings := Res;
  end;

begin
  ScrollingTextStart := TEcPhrase.Create(
    EcPPart(rsScrollingText, ecMessage),
    EcPPart(rsColon, ecMessage),
    EcPPart(GetSettings, ecFaded)
  );
end;

function TEcStringiser.ScrollingTextLine(Params: TJSONArray): TEcPhrase;
begin
  ScrollingTextLine := TEcPhrase.Create(
    EcPPart(rsScrollingText, ecInvisible),
    EcPPart(rsColon, ecMessage),
    EcPPart(Params.Strings[0], ecString)
  );
end;

function TEcStringiser.SetSwitches(Params: TJSONArray): TEcPhrase;
  function GetActionDesc: String;
  var
    Switch1, Switch2, FormatString: String;
  begin
    if Params.Integers[0] = Params.Integers[1] then begin
      Switch1 := Db.GetSwitchName(Params.Integers[1]);

      if Params.Booleans[2] then
        FormatString := rsSetSwitches_SingleOff
      else
        FormatString := rsSetSwitches_SingleOn;

      GetActionDesc := FormatString.Format([Switch1]);
    end else begin
      Switch1 := Format('%.4d', [Params.Integers[0]]);
      Switch2 := Format('%.4d', [Params.Integers[1]]);

      if Params.Booleans[2] then
        FormatString := rsSetSwitches_ManyOff
      else
        FormatString := rsSetSwitches_ManyOn;

      GetActionDesc := FormatString.Format([Switch1, Switch2]);
    end;
  end;

begin
  SetSwitches := TEcPhrase.Create(
    EcPPart(rsSetSwitches, ecProgression),
    EcPPart(rsColon, ecProgression),
    EcPPart(GetActionDesc, ecProgression)
  );
end;

function TEcStringiser.SetVariables(Params: TJSONArray): TEcPhrase;
  function GetVarText: String;
  begin
    if Params.Integers[0] = Params.Integers[1] then
      GetVarText := rsSetVariables_singleVar.Format([Db.GetVariableName(Params.Integers[0])])
    else
      GetVarText := rsSetVariables_manyVars.Format([
                 Format('%.4d', [Params.Integers[0]]),
                 Format('%.4d', [Params.Integers[1]])
      ])
  end;

  function GetOperand: String;
  begin
    case Params.Integers[3] of
      0: GetOperand := IntToStr(Params.Integers[4]);
      1: GetOperand := rsSetVariables_indirect.Format([Db.GetVariableName(Params.Integers[4])]);
      2: GetOperand := rsSetVariables_random.Format([Params.Integers[4], Params.Integers[5]]);
      3: GetOperand := SetVar_GetGameData(Params, Db);
      4: GetOperand := Params.Strings[4];
    else
      GetOperand := rsUnknownParameter;
    end;


  end;

  function GetAction: String;
  var
    Template: String;
  begin
    case Params.Integers[2] of
      0: Template := rsSetVariables_set;
      1: Template := rsSetVariables_add;
      2: Template := rsSetVariables_sub;
      3: Template := rsSetVariables_mul;
      4: Template := rsSetVariables_div;
      5: Template := rsSetVariables_mod;
    else
      Template := '%0-s ??? %1-s';
    end;

    GetAction := Template.Format([
      GetVarText,
      GetOperand
    ]);
  end;
begin
  SetVariables := TEcPhrase.Create(
    EcPPart(rsSetVariables, ecProgression),
    EcPPart(rsColon, ecProgression),
    EcPPart(GetAction, ecProgression)
  );
end;

function TEcStringiser.SetSelfSwitch(Params: TJSONArray): TEcPhrase;
  function GetAction: String;
  begin
    case Params.Integers[1] of
      0: GetAction := rsSetSelfSwitch_on.Format([InnerSelfSwitchNameToUserName(Params.Strings[0])]);
      1: GetAction := rsSetSelfSwitch_off.Format([InnerSelfSwitchNameToUserName(Params.Strings[0])]);
    else
      GetAction := rsUnknownParameter;
    end;
  end;
begin
  SetSelfSwitch := TEcPhrase.Create(
    EcPPart(rsSetSelfSwitch, ecProgression),
    EcPPart(rsColon, ecProgression),
    EcPPart(GetAction, ecProgression)
  );
end;

function TEcStringiser.FormatTimerTime(TotalSecs: Integer): String;
var
  Min, Sec: Integer;
begin
  Min := TotalSecs div 60;
  Sec := TotalSecs mod 60;

  if (Min <> 0) and (Sec <> 0) then
    FormatTimerTime := rsControlTimer_minsec.Format([Min, Sec])
  else if Min <> 0 then
    FormatTimerTime := rsControlTimer_min.Format([Min])
  else
    FormatTimerTime := rsControlTimer_sec.Format([Sec])
end;

function TEcStringiser.CurrencyName: String;
var
  Currency: String;
begin
  Currency := Db.System.Strings['currencyUnit'];
  if Trim(Currency) = '' then
    Currency := rsCurrency;

  CurrencyName := Currency;
end;

function TEcStringiser.Direction(DirCode: Integer): String;
begin
  case DirCode  of
    2: Direction := rsDirBottom;
    4: Direction := rsDirLeft;
    6: Direction := rsDirRight;
    8: Direction := rsDirTop;
  else
    Direction := rsUnknownParameter;
  end;
end;

function TEcStringiser.Vehicle(Code: Integer): String;
begin
  case Code of
    0: Vehicle := rsVehicleBoat;
    1: Vehicle := rsVehicleShip;
    2: Vehicle := rsVehicleAirship;
  else
    Vehicle := rsUnknownParameter;
  end;
end;

function TEcStringiser.TroopMemberName(MemberIndex: Integer): String;
var
  MemberName: String = '';
  Number: String;
  MemberId: Integer;
begin
  if MemberIndex = -1 then
    TroopMemberName := rsWholeTroop
  else begin
    Number := rsNumber.Format([MemberIndex + 1]);

    if (Troop <> nil) and (MemberIndex < Troop.Arrays['members'].Count) then begin
      MemberId := Troop.Arrays['members'].Objects[MemberIndex].Integers['enemyId'];
      MemberName := Db.GetEnemyName(MemberId, False);
    end;

    if MemberName <> '' then
      TroopMemberName := Number + rsSpace + MemberName
    else
      TroopMemberName := Number
  end;
end;

function TEcStringiser.ControlTimer(Params: TJSONArray): TEcPhrase;
  function GetAction: String;
  begin
    case Params.Integers[0] of
      0: GetAction := rsControlTimer_start + rsComma + FormatTimerTime(Params.Integers[1]);
      1: GetAction := rsControlTimer_stop;
    else
      GetAction := rsUnknownParameter;
    end;
  end;

begin
  ControlTimer := TEcPhrase.Create(
    EcPPart(rsControlTimer, ecProgression),
    EcPPart(rsColon, ecProgression),
    EcPPart(GetAction, ecProgression)
  );
end;

function TEcStringiser.ConditionalBranch(Params: TJSONArray): TEcPhrase;
  function GetAction: String;
    function SwitchAction: String;
    var
      FmtStr: String;
    begin
      if Params.Integers[2] = 0 then
        FmtStr := rsConditionalBranch_switchIsOn
      else
        FmtStr := rsConditionalBranch_switchIsOff;

        SwitchAction := FmtStr.Format([Db.GetSwitchName(Params.Integers[1])]);
    end;

    function VarAction: String;
    var
      Operand, Arg: String;
    begin
      Operand := Db.GetVariableName(Params.Integers[1]);

      if Params.Integers[2] = 0 then
        Arg := IntToStr(Params.Integers[3])
      else
        Arg := rsConditionalBranch_varIndirect.Format([Params.Integers[3]]);

      case Params.Integers[4] of
        0: VarAction := rsConditionalBranch_varEq.Format([Operand, Arg]);
        1: VarAction := rsConditionalBranch_varGtEq.Format([Operand, Arg]);
        2: VarAction := rsConditionalBranch_varLtEq.Format([Operand, Arg]);
        3: VarAction := rsConditionalBranch_varGt.Format([Operand, Arg]);
        4: VarAction := rsConditionalBranch_varLt.Format([Operand, Arg]);
        5: VarAction := rsConditionalBranch_varNeq.Format([Operand, Arg]);
      else
        VarAction := rsUnknownParameter;
      end;
    end;

    function SelfSwitchAction: String;
    begin
      if Params.Integers[2] = 0 then
        SelfSwitchAction := rsConditionalBranch_selfSwitchIsOn.Format([InnerSelfSwitchNameToUserName(Params.Strings[1])])
      else
        SelfSwitchAction := rsConditionalBranch_selfSwitchIsOff.Format([InnerSelfSwitchNameToUserName(Params.Strings[1])]);
    end;

    function TimerAction: String;
    var
      Time: String;
    begin
      Time := FormatTimerTime(Params.Integers[1]);
      if Params.Integers[2] = 0 then
        TimerAction := rsConditionalBranch_timerGtEq.Format([Time])
      else
        TimerAction := rsConditionalBranch_timerLtEq.Format([Time])
    end;

    function ActorAction: String;
    var
      Actor: String;
    begin
      Actor := Db.GetActorName(Params.Integers[1], False);
      case Params.Integers[2] of
        0: ActorAction := rsConditionalBranch_actorInParty.Format([Actor]);
        1: ActorAction := rsConditionalBranch_actorName.Format([Actor, Params.Strings[3]]);
        2: ActorAction := rsConditionalBranch_actorClass.Format([Actor, Db.GetClassName(Params.Integers[3])]);
        3: ActorAction := rsConditionalBranch_actorSkills.Format([Actor, Db.GetSkillName(Params.Integers[3])]);
        4: ActorAction := rsConditionalBranch_actorWeapon.Format([Actor, Db.GetWeaponName(Params.Integers[3])]);
        5: ActorAction := rsConditionalBranch_actorArmour.Format([Actor, Db.GetArmourName(Params.Integers[3])]);
        6: ActorAction := rsConditionalBranch_actorState.Format([Actor, Db.GetStateName(Params.Integers[3])]);
      else
        ActorAction := rsUnknownParameter;
      end;
    end;

    function EnemyAction: String;
    var
      Enemy: String;
      EnemyId: Integer;
    begin
      if (Troop <> nil) and (Params.Integers[1] < Troop.Arrays['members'].Count) then begin
        EnemyId := Troop.Arrays['members'].Objects[Params.Integers[1]].Integers['enemyId'];
        Enemy := rsEnemyNumberName.Format([Params.Integers[1] + 1, Db.Enemies.Objects[EnemyId].Strings['name']]);
      end else
        Enemy := rsEnemyNumber.Format([Params.Integers[1] + 1]);

      case Params.Integers[2] of
        0: EnemyAction := rsConditionalBranch_enemyAppeared.Format([Enemy]);
        1: EnemyAction := rsConditionalBranch_enemyState.Format([Enemy, Db.GetStateName(Params.Integers[3])]);
      else
        EnemyAction := rsUnknownParameter;
      end;
    end;

    function CharAction: String;
    var
      CharName: String;
    begin
      CharName := FormatChar(Params.Integers[1]);
      case Params.Integers[2] of
        2: CharAction := rsConditionalBranch_charDown.Format([CharName]);
        4: CharAction := rsConditionalBranch_charLeft.Format([CharName]);
        6: CharAction := rsConditionalBranch_charRight.Format([CharName]);
        8: CharAction := rsConditionalBranch_charUp.Format([CharName]);
      else
        CharAction := rsUnknownParameter;
      end;
    end;

    function GoldAction: String;
    var
      Currency, Sum: String;
    begin
      Currency := CurrencyName;
      Sum := IntToStr(Params.Integers[1]);
      case Params.Integers[2] of
        0: GoldAction := rsConditionalBranch_goldGtEq.Format([Currency, Sum]);
        1: GoldAction := rsConditionalBranch_goldLtEq.Format([Currency, Sum]);
        2: GoldAction := rsConditionalBranch_goldLt.Format([Currency, Sum]);
      else
        GoldAction := rsUnknownParameter + rsComma + Sum;
      end;
    end;

    function ItemAction: String;
    begin
      ItemAction := rsSetVariables_item.Format([Db.GetItemName(Params.Integers[1])]);
    end;

    function WeaponAction: String;
    begin
      WeaponAction := rsSetVariables_item.Format([Db.GetWeaponName(Params.Integers[1])]);
    end;

    function ArmourAction: String;
    begin
      ArmourAction := rsSetVariables_item.Format([Db.GetArmourName(Params.Integers[1])]);
    end;

    function ButtonAction: String;
    var
      ButtonName: String;
    begin
      ButtonName := GetButtonName(Params.Strings[1]);
      ButtonAction := rsConditionalBranch_button.Format([ButtonName]);
    end;

    function ScriptAction: String;
    begin
      ScriptAction := Params.Strings[1];
    end;

    function VehicleAction: String;
    begin
      case Params.Integers[1] of
        0: VehicleAction := rsConditionalBranch_vehicleBoat;
        1: VehicleAction := rsConditionalBranch_vehicleShip;
        2: VehicleAction := rsConditionalBranch_vehicleAirship;
      else
        VehicleAction := rsUnknownParameter;
      end;
    end;

  begin
    case Params.Integers[0] of
      0: GetAction := SwitchAction;
      1: GetAction := VarAction;
      2: GetAction := SelfSwitchAction;
      3: GetAction := TimerAction;
      4: GetAction := ActorAction;
      5: GetAction := EnemyAction;
      6: GetAction := CharAction;
      7: GetAction := GoldAction;
      8: GetAction := ItemAction;
      9: GetAction := WeaponAction;
      10: GetAction := ArmourAction;
      11: GetAction := ButtonAction;
      12: GetAction := ScriptAction;
      13: GetAction := VehicleAction;
    else
      GetAction := rsUnknownParameter;
    end;
  end;

  function GetAdditionalData: String;
  begin
    GetAdditionalData := '';
    if Params.Integers[0] in [9, 10] then begin
      if Params.Booleans[2] then
        GetAdditionalData := rsIncludingEquipment;
    end;
  end;

begin
  ConditionalBranch := TEcPhrase.Create(
    EcPPart(rsConditionalBranch, ecFlow),
    EcPPart(rsSpace, ecFlow),
    EcPPart(GetAction, ecFlow),
    EcPPart(rsSpace, ecInvisible),
    EcPPart(GetAdditionalData, ecFaded)
  );
end;

function TEcStringiser.LabelEc(Params: TJSONArray): TEcPhrase;
begin
  LabelEc := TEcPhrase.Create(
    EcPPart(rsLabel, ecFlow),
    EcPPart(rsColon, ecFlow),
    EcPPart(Params.Strings[0], ecFlow)
  );
end;

function TEcStringiser.GotoEc(Params: TJSONArray): TEcPhrase;
begin
  GotoEc := TEcPhrase.Create(
    EcPPart(rsGoto, ecFlow),
    EcPPart(rsColon, ecFlow),
    EcPPart(Params.Strings[0], ecFlow)
  );
end;

function TEcStringiser.CallCommonEvent(Params: TJSONArray): TEcPhrase;
begin
  CallCommonEvent := TEcPhrase.Create(
    EcPPart(rsCallCommonEvent, ecFlow),
    EcPPart(rsColon, ecFlow),
    EcPPart(Db.GetCommonEventName(Params.Integers[0]), ecFlow)
  );
end;

function TEcStringiser.Comment(Params: TJSONArray): TEcPhrase;
begin
  Comment := TEcPhrase.Create(
    EcPPart(rsComment, ecComment),
    EcPPart(rsColon, ecComment),
    EcPPart(Params.Strings[0], ecComment)
  );
end;

function TEcStringiser.CommentContinuation(Params: TJSONArray): TEcPhrase;
begin
  CommentContinuation := TEcPhrase.Create(
    EcPPart(rsComment, ecInvisible),
    EcPPart(rsColon, ecComment),
    EcPPart(Params.Strings[0], ecComment)
  );
end;

function TEcStringiser.ChangeGold(Params: TJSONArray): TEcPhrase;
  function GetArgument: String;
  begin
    case Params.Integers[1] of
      0: GetArgument := rsChangeGold_currency.Format([Params.Integers[2], CurrencyName]);
      1: GetArgument := rsIndirectVariable.Format([Db.GetVariableName(Params.Integers[2])]);
    else
      GetArgument := rsUnknownParameter;
    end;
  end;

  function GetAction: String;
  begin
    case Params.Integers[0] of
      0: GetAction := rsChangeGold_add.Format([GetArgument]);
      1: GetAction := rsChangeGold_remove.Format([GetArgument]);
    else
      GetAction := rsUnknownParameter;
    end;
  end;

begin
  ChangeGold := TEcPhrase.Create(
    EcPPart(rsChangeGold, ecParty),
    EcPPart(rsColon, ecParty),
    EcPPart(GetAction, ecParty)
  );
end;

function TEcStringiser.ChangeItemsWeaponsArmours_GetAction(Params: TJSONArray;
  ItemName: String): String;
  function GetValue: String;
  begin
    case Params.Integers[2] of
      0: GetValue := IntToStr(Params.Integers[3]);
      1: GetValue := rsIndirectVariable.Format([Db.GetVariableName(Params.Integers[3])]);
    else
      GetValue := rsUnknownParameter;
    end;
  end;

begin
  case Params.Integers[1] of
    0: Result := rsChangeItemsWeaponsArmours_add.Format([GetValue, ItemName]);
    1: Result := rsChangeItemsWeaponsArmours_remove.Format([GetValue, ItemName]);
  else
    Result := rsUnknownParameter;
  end;

end;

function TEcStringiser.ChangeWeaponsArmours_AddIncludingEquipment(
  Phrase: TEcPhrase; Params: TJSONArray): TEcPhrase;
var
  OldLength: Integer;
begin
  OldLength := Length(Phrase);
  if Params.Booleans[4] = True then begin
    SetLength(Phrase, OldLength + 2);
    Phrase[OldLength] := EcPPart(rsSpace, ecFaded);
    Phrase[OldLength + 1] := EcPPart(rsIncludingEquipment, ecFaded);
  end;

  Result := Phrase;
end;

function TEcStringiser.ChangeItems(Params: TJSONArray): TEcPhrase;
begin
  ChangeItems := TEcPhrase.Create(
    EcPPart(rsChangeItems, ecParty),
    EcPPart(rsColon, ecParty),
    EcPPart(ChangeItemsWeaponsArmours_GetAction(Params, Db.GetItemName(Params.Integers[0], False)), ecParty)
  );
end;

function TEcStringiser.ChangeWeapons(Params: TJSONArray): TEcPhrase;
begin
  ChangeWeapons := ChangeWeaponsArmours_AddIncludingEquipment(
    TEcPhrase.Create(
      EcPPart(rsChangeWeapons, ecParty),
      EcPPart(rsColon, ecParty),
      EcPPart(ChangeItemsWeaponsArmours_GetAction(Params, Db.GetWeaponName(Params.Integers[0], False)), ecParty)
    ),
    Params
  );
end;

function TEcStringiser.ChangeArmours(Params: TJSONArray): TEcPhrase;
begin
  ChangeArmours := ChangeWeaponsArmours_AddIncludingEquipment(
    TEcPhrase.Create(
      EcPPart(rsChangeArmours, ecParty),
      EcPPart(rsColon, ecParty),
      EcPPart(ChangeItemsWeaponsArmours_GetAction(Params, Db.GetArmourName(Params.Integers[0], False)), ecParty)
    ),
    Params
  );
end;

function TEcStringiser.ChangeParty(Params: TJSONArray): TEcPhrase;
  function GetAction: String;
  var
    Actor: String;
  begin
    Actor := Db.GetActorName(Params.Integers[0], False);
    case Params.Integers[1] of
      0: GetAction := rsChangePartyMember_add.Format([Actor]);
      1: GetAction := rsChangePartyMember_remove.Format([Actor]);
    else
      GetAction := rsUnknownParameter;
    end;
  end;

  function FadedText: String;
  begin
    if (Params.Integers[1] = 0) and Params.Booleans[2] then
      FadedText := rsChangePartyMember_reset
    else
      FadedText := '';
  end;

begin
  ChangeParty := TEcPhrase.Create(
    EcPPart(rsChangePartyMember, ecParty),
    EcPPart(rsColon, ecParty),
    EcPPart(GetAction, ecParty),
    EcPPart(rsSpace, ecFaded),
    EcPPart(FadedText, ecFaded)
  );
end;

function TEcStringiser.ActorEcs_GetActor(Params: TJSONArray): String;
begin
  case Params.Integers[0] of
    0: if Params.Integers[1] > 0 then
         ActorEcs_GetActor := Db.GetActorName(Params.Integers[1], False)
       else
         ActorEcs_GetActor := rsEntireParty;
    1: ActorEcs_GetActor := rsIndirectVariable.Format([Db.GetVariableName(Params.Integers[1])]);
  else
    ActorEcs_GetActor := rsUnknownParameter;
  end;
end;

function TEcStringiser.ChangeHp_AddAllowKnockout(Phrase: TEcPhrase;
  Params: TJSONArray): TEcPhrase;
var
  OldLength: Integer;
begin
  OldLength := Length(Phrase);
  if Params.Booleans[4] = True then begin
    SetLength(Phrase, OldLength + 2);
    Phrase[OldLength] := EcPPart(rsSpace, ecFaded);
    Phrase[OldLength + 1] := EcPPart(rsChangeHp_allowKnockout, ecFaded);
  end;

  Result := Phrase;
end;

function TEcStringiser.ChangeHpMpTp(Params: TJSONArray; EcName,
  PointName: String; HasKnockout: Boolean): TEcPhrase;
  function GetValue: String;
  begin
    case Params.Integers[3] of
      0: GetValue := rsPoints.Format([Params.Integers[4], PointName]);
      1: GetValue := rsIndirectVariable.Format([Db.GetVariableName(Params.Integers[4])]);
    else
      GetValue := rsUnknownParameter;
    end;
  end;

  function GetAction: String;
  begin
    case Params.Integers[2] of
      0: Result := rsChangeHpMpTp_add.Format([ActorEcs_GetActor(Params), GetValue]);
      1: Result := rsChangeHpMpTp_remove.Format([ActorEcs_GetActor(Params), GetValue]);
    else
      Result := rsUnknownParameter;
    end;

  end;

var
  Phrase: TEcPhrase;
begin
  Phrase := TEcPhrase.Create(
    EcPPart(ecName, ecActor),
    EcPPart(rsColon, ecActor),
    EcPPart(GetAction, ecActor)
  );

  if HasKnockout then
    ChangeHpMpTp := ChangeHp_AddAllowKnockout(Phrase, Params)
  else
    ChangeHpMpTp := Phrase
end;

function TEcStringiser.ChangeState(Params: TJSONArray): TEcPhrase;
  function GetAction: String;
  var
    ActorName, StateName: String;
  begin
    ActorName := ActorEcs_GetActor(Params);
    StateName := Db.GetStateName(Params.Integers[3]);

    case Params.Integers[2] of
      0: Result := rsChangeState_add.Format([ActorName, StateName]);
      1: Result := rsChangeState_remove.Format([ActorName, StateName]);
    else
      Result := rsUnknownParameter;
    end;
  end;
begin
  ChangeState := TEcPhrase.Create(
    EcPPart(rsChangeState, ecActor),
    EcPPart(rsColon, ecActor),
    EcPPart(GetAction, ecActor)
  );
end;

function TEcStringiser.CompleteRecovery(Params: TJSONArray): TEcPhrase;
var
  Target: String;
begin
  Target :=  ActorEcs_GetActor(Params);
  CompleteRecovery := TEcPhrase.Create(
    EcPPart(rsCompleteRecovery, ecActor),
    EcPPart(rsColon, ecActor),
    EcPPart(Target, ecActor)
  );
end;

function TEcStringiser.ChangeExpLevel(Params: TJSONArray; IsLevel: Boolean
  ): TEcPhrase;
  function GetValue: String;
  begin
    case Params.Integers[3] of
      0: GetValue := IntToStr(Params.Integers[4]);
      1: GetValue := rsIndirectVariable.Format([Db.GetVariableName(Params.Integers[4])]);
    else
      GetValue := rsUnknownParameter;
    end;
  end;

  function GetAction: String;
  var
    ActorName: String;
  begin
    ActorName := ActorEcs_GetActor(Params);

    case Params.Integers[2] of
      0: Result := rsChangeExpLevel_add.Format([ActorName, GetValue]);
      1: Result := rsChangeExpLevel_remove.Format([ActorName, GetValue]);
    else
      Result := rsUnknownParameter;
    end;
  end;

  function GetFaded: String;
  begin
    if (Params.Integers[2] = 1) and Params.Booleans[5] then
      GetFaded := rsShowLevelUp
    else
      GetFaded := '';
  end;

var
  CommandName: String;
begin
  if IsLevel then
    CommandName := rsChangeLevel
  else
    CommandName := rsChangeExp;

  ChangeExpLevel := TEcPhrase.Create(
    EcPPart(CommandName, ecActor),
    EcPPart(rsColon, ecActor),
    EcPPart(GetAction, ecActor),
    EcPPart(rsSpace, ecFaded),
    EcPPart(GetFaded, ecFaded)
  );
end;

function TEcStringiser.ChangeParam(Params: TJSONArray): TEcPhrase;
  function GetValue: String;
  begin
    case Params.Integers[4] of
      0: GetValue := IntToStr(Params.Integers[5]);
      1: GetValue := rsIndirectVariable.Format([Db.GetVariableName(Params.Integers[5])]);
    else
      GetValue := rsUnknownParameter;
    end;
  end;

  function GetAction: String;
  var
    Actor: String;
    Param: String;
  begin
    Actor := ActorEcs_GetActor(Params);
    Param := Db.System.Objects['terms'].Arrays['params'].Strings[Params.Integers[2]];

    case Params.Integers[3] of
      0: GetAction := rsChangeParam_add.Format([Actor, Param, GetValue]);
      1: GetAction := rsChangeParam_remove.Format([Actor, Param, GetValue]);
    else
      GetAction := rsUnknownParameter;
    end;
  end;
begin
  ChangeParam := TEcPhrase.Create(
    EcPPart(rsChangeParam, ecActor),
    EcPPart(rsColon, ecActor),
    EcPPart(GetAction, ecActor)
  );
end;

function TEcStringiser.ChangeSkill(Params: TJSONArray): TEcPhrase;
  function GetAction: String;
  var
    Actor, Skill: String;
  begin
    Actor := ActorEcs_GetActor(Params);
    Skill := Db.GetSkillName(Params.Integers[3], False);

    case Params.Integers[2] of
      0: GetAction := rsChangeSkill_learn.Format([Actor, Skill]);
      1: GetAction := rsChangeSkill_forget.Format([Actor, Skill]);
    else
      GetAction := rsUnknownParameter;
    end;
  end;

begin
  ChangeSkill := TEcPhrase.Create(
    EcPPart(rsChangeSkill, ecActor),
    EcPPart(rsColon, ecActor),
    EcPPart(GetAction, ecActor)
  );
end;

function TEcStringiser.ChangeEquipment(Params: TJSONArray): TEcPhrase;
  function GetAction: String;
  var
    IsWeapon: Boolean;
    ActorId, SlotId: Integer;
    Actor, Slot, Item: String;
  begin
    ActorId := Params.Integers[0];
    Actor := Db.GetActorName(ActorId, False);
    SlotId := Params.Integers[1];
    Slot := Db.GetEquipTypeName(SlotId);

    IsWeapon := (SlotId = 1) or ((SlotId=2) and Db.ActorHasTwoWeapons(ActorId));

    if Params.Integers[2] > 0 then begin
      if IsWeapon then
        Item := Db.GetWeaponName(Params.Integers[2])
      else
        Item := Db.GetArmourName(Params.Integers[2]);

      GetAction := rsChangeEquipment_defined.Format([Actor, Slot, Item]);
    end else
      GetAction := rsChangeEquipment_none.Format([Actor, Slot]);
  end;

begin
  ChangeEquipment := TEcPhrase.Create(
    EcPPart(rsChangeEquipment, ecActor),
    EcPPart(rsColon, ecActor),
    EcPPart(GetAction, ecActor)
  );
end;

function TEcStringiser.ChangeName(Params: TJSONArray): TEcPhrase;
var
  Actor, NewName: String;
begin
  Actor := Db.GetActorName(Params.Integers[0]);
  NewName := Params.Strings[1];

  ChangeName := TEcPhrase.Create(
    EcPPart(rsChangeName, ecActor),
    EcPPart(rsColon, ecActor),
    EcPPart(rsChangeName_expanation.Format([Actor, NewName]), ecActor)
  );
end;

function TEcStringiser.ChangeClass(Params: TJSONArray): TEcPhrase;
  function GetFaded: String;
  begin
    if Params.Booleans[2] then
      GetFaded := rsChangeClass_keepLevel
    else
      GetFaded := rsChangeClass_dontKeepLevel;
  end;

var
  Actor, NewClass: String;
begin
  Actor := Db.GetActorName(Params.Integers[0]);
  NewClass := Db.GetClassName(Params.Integers[1]);

  ChangeClass := TEcPhrase.Create(
    EcPPart(rsChangeClass, ecActor),
    EcPPart(rsColon, ecActor),
    EcPPart(rsChangeClass_explanation.Format([Actor, NewClass]), ecActor),
    EcPPart(rsSpace, ecFaded),
    EcPPart(GetFaded, ecFaded)
  );
end;

function TEcStringiser.ChangeNickname(Params: TJSONArray): TEcPhrase;
var
  Actor, NewNickname: String;
begin
  Actor := Db.GetActorName(Params.Integers[0]);
  NewNickname := Params.Strings[1];

  ChangeNickname := TEcPhrase.Create(
    EcPPart(rsChangeNickname, ecActor),
    EcPPart(rsColon, ecActor),
    EcPPart(rsChangeNicknameProfile_explanation.Format([Actor, NewNickname]), ecActor)
  );
end;

function TEcStringiser.ChangeProfile(Params: TJSONArray): TEcPhrase;
var
  Actor, NewProfile: String;
begin
  Actor := Db.GetActorName(Params.Integers[0]);
  NewProfile := StringReplace(Params.Strings[1], #$D#$A, ' ', [rfReplaceAll]);
  NewProfile := StringReplace(NewProfile, #$A, ' ', [rfReplaceAll]);

  ChangeProfile := TEcPhrase.Create(
    EcPPart(rsChangeProfile, ecActor),
    EcPPart(rsColon, ecActor),
    EcPPart(rsChangeNicknameProfile_explanation.Format([Actor, NewProfile]), ecActor)
  );
end;

function TEcStringiser.TransferPlayer(Params: TJSONArray): TEcPhrase;
  function GetLocation: String;
  var
    MapId, X, Y: String;
  begin
    if Params.Integers[0] = 0 then begin
      MapId := Game.MapInfos.GetMapName(Params.Integers[1]);
      X := IntToStr(Params.Integers[2]);
      Y := IntToStr(Params.Integers[3]);
    end else begin
      MapId := rsIndirectVariable.Format([Db.GetVariableName(Params.Integers[1])]);
      X := rsIndirectVariable.Format([Db.GetVariableName(Params.Integers[2])]);
      Y := rsIndirectVariable.Format([Db.GetVariableName(Params.Integers[3])]);
    end;

    GetLocation := rsTransferPlayer_explanation.Format([MapId, X, Y]);
  end;

  function GetFaded: String;
  var
    Fade: String = '';
    Dir: String = '';
  begin
    if Params.Integers[4] > 0 then
      Dir := Direction(Params.Integers[4]);

    if Params.Integers[5] = 1 then
      Fade := rsTransferPlayer_fadeWhite;
    if Params.Integers[5] = 2 then
      Fade := rsTransferPlayer_fadeNone;

    if (Dir <> '') and (Fade <> '') then
      GetFaded := rsOpenBracket + Dir + rsComma + Fade + rsCloseBracket
    else if (Dir <> '') then
      GetFaded := rsOpenBracket + Dir + rsCloseBracket
    else if (Fade <> '') then
      GetFaded := rsOpenBracket + Fade + rsCloseBracket
    else
      GetFaded := '';
  end;

begin
   TransferPlayer := TEcPhrase.Create(
    EcPPart(rsTransferPlayer, ecMove),
    EcPPart(rsColon, ecMove),
    EcPPart(GetLocation, ecMove),
    EcPPart(rsSpace, ecFaded),
    EcPPart(GetFaded, ecFaded)
  );
end;

function TEcStringiser.SetVehicleLocation(Params: TJSONArray): TEcPhrase;
var
  MapId, X, Y: String;

  procedure FillLocation;
  begin
    if Params.Integers[1] = 0 then begin
      MapId := Game.MapInfos.GetMapName(Params.Integers[2]);
      X := IntToStr(Params.Integers[3]);
      Y := IntToStr(Params.Integers[4]);
    end else begin
      MapId := rsIndirectVariable.Format([Db.GetVariableName(Params.Integers[2])]);
      X := rsIndirectVariable.Format([Db.GetVariableName(Params.Integers[3])]);
      Y := rsIndirectVariable.Format([Db.GetVariableName(Params.Integers[4])]);
    end;
  end;

begin
  FillLocation;

  SetVehicleLocation := TEcPhrase.Create(
   EcPPart(rsSetVehicleLocation, ecMove),
   EcPPart(rsColon, ecMove),
   EcPPart(rsSetVehicleLocation_explanation.Format([
             Vehicle(Params.Integers[0]), MapId, X, Y
           ]), ecMove)
 );
end;

function TEcStringiser.SetEventLocation(Params: TJSONArray): TEcPhrase;
  function GetLocation: String;
  begin
    case Params.Integers[1] of
      0: GetLocation := rsOpenBracket + IntToStr(Params.Integers[2]) + rsComma + IntToStr(Params.Integers[3]) + rsCloseBracket;
      1: GetLocation := rsOpenBracket + rsIndirectVariable.Format([Db.GetVariableName(Params.Integers[2])])
        + rsComma + rsIndirectVariable.Format([Db.GetVariableName(Params.Integers[2])]) + rsCloseBracket;
      2: GetLocation := rsSetEventLocation_exchange.Format([FormatChar(Params.Integers[2])]);
    else
      GetLocation := rsUnknownParameter;
    end
  end;
begin
  SetEventLocation := TEcPhrase.Create(
   EcPPart(rsSetEventLocation.Format([FormatChar(Params.Integers[0]), GetLocation]), ecMove)
  );
end;

function TEcStringiser.ScrollMap(Params: TJSONArray): TEcPhrase;
begin
  ScrollMap := TEcPhrase.Create(
   EcPPart(rsScrollMap.Format([Direction(Params.Integers[0]), Params.Integers[1], Params.Integers[2]]), ecMove)
 );
end;

function TEcStringiser.SetMoveRoute(Params: TJSONArray): TEcPhrase;
  function GetFaded: String;
  var
    Res: String = '';
    Route: TJSONObject;
  begin
    Route := Params.Objects[1];
    if Route.Booleans['repeat'] then
      Res := rsSetMoveRoute_repeat;
    if Route.Booleans['skippable'] then begin
      if Res <> '' then
        Res := Res + rsComma;
      Res := Res + rsSetMoveRoute_skip;
    end;
    if Route.Booleans['wait'] then begin
      if Res <> '' then
        Res := Res + rsComma;
      Res := Res + rsSetMoveRoute_wait;
    end;

    if Res <> '' then
      Res := rsOpenBracket + Res + rsCloseBracket;
    GetFaded := Res;
  end;

begin
  SetMoveRoute := TEcPhrase.Create(
   EcPPart(rsSetMoveRoute, ecMove),
   EcPPart(rsColon, ecMove),
   EcPPart(FormatChar(Params.Integers[0]), ecMove),
   EcPPart(rsSpace, ecFaded),
   EcPPart(GetFaded, ecFaded)
 );
end;

function TEcStringiser.SetMoveRouteLine(Params: TJSONArray): TEcPhrase;
begin
  SetMoveRouteLine := TEcPhrase.Create(
   EcPPart(rsSetMoveRoute, ecInvisible),
   EcPPart(rsColon, ecMove),
   EcPPart('◇ ' + Self.MoveRouteStringiser.StringizeMoveCommand(Params.Objects[0]), ecMove)
 );
end;

function TEcStringiser.ShowAnimation(Params: TJSONArray): TEcPhrase;
begin
  ShowAnimation := AddWait(Params, 2,
    TEcPhrase.Create(
     EcPPart(rsShowAnimation.Format([
         FormatChar(Params.Integers[0]),
         Db.GetAnimName(Params.Integers[1])
       ]), ecChar)
     )
   );
end;

function TEcStringiser.ShowEmotionBalloon(Params: TJSONArray): TEcPhrase;
begin
  ShowEmotionBalloon := AddWait(Params, 2,
    TEcPhrase.Create(
     EcPPart(rsEmotionBalloonAnimation.Format([
         FormatChar(Params.Integers[0]),
         GetBalloonName(Params.Integers[1])
       ]), ecChar)
     )
  );

end;

function TEcStringiser.ShowMovePicture_Params(Params: TJSONArray): String;
  function Position: String;
  var
    X, Y: String;
  begin
    if Params.Integers[3] = 0 then begin
      X := IntToStr(Params.Integers[4]);
      Y := IntToStr(Params.Integers[5]);
    end else begin
      X := rsIndirectVariable.Format([Db.GetVariableName(Params.Integers[4])]);
      Y := rsIndirectVariable.Format([Db.GetVariableName(Params.Integers[5])]);
    end;

    case Params.Integers[2] of
      0: Position := rsShowMovePicture_topLeftPos.Format([X, Y]);
      1: Position := rsShowMovePicture_centerPos.Format([X, Y]);
    else
      Position := rsUnknownParameter;
    end;
  end;
begin
  ShowMovePicture_Params := rsShowMovePicture_params.Format([
    Position,
    Params.Integers[6], Params.Integers[7],
    Params.Integers[8],
    GetBlendModeName(Params.Integers[9])
  ]);
end;

function TEcStringiser.ShowPicture(Params: TJSONArray): TEcPhrase;
begin
  ShowPicture := TEcPhrase.Create(
   EcPPart(rsShowPicture.Format([
       Params.Integers[0],
       Params.Strings[1],
       ShowMovePicture_Params(Params)
     ]), ecPic)
  );
end;

function TEcStringiser.MovePicture(Params: TJSONArray): TEcPhrase;
begin
  MovePicture := AddWait(Params, 11,
    TEcPhrase.Create(
     EcPPart(rsShowPicture.Format([
         Params.Integers[0],
         ShowMovePicture_Params(Params),
         rsFrames.Format([Params.Integers[10]])
       ]), ecPic)
    )
  );
end;

function TEcStringiser.RotatePicture(Params: TJSONArray): TEcPhrase;
begin
  RotatePicture := TEcPhrase.Create(
    EcPPart(rsRotatePicture.Format([
      Params.Integers[0],
      Params.Integers[1]
    ]), ecPic)
  );
end;

function TEcStringiser.TintPicture(Params: TJSONArray): TEcPhrase;
var
  MainText: String;
begin
  MainText := rsTintPicture.Format([
    Params.Integers[0],
    Params.Arrays[1].Integers[0],
    Params.Arrays[1].Integers[1],
    Params.Arrays[1].Integers[2],
    Params.Arrays[1].Integers[3],
    rsFrames.Format([Params.Integers[3]])
  ]);

  TintPicture := AddWait(Params, 3,
    SimpleEcPhrase(MainText, ecPic)
  );
end;

function TEcStringiser.ErasePicture(Params: TJSONArray): TEcPhrase;
begin
  ErasePicture := TEcPhrase.Create(
    EcPPart(rsErasePicture.Format([
      Params.Integers[0]
    ]), ecPic)
  );
end;

function TEcStringiser.Wait(Params: TJSONArray): TEcPhrase;
begin
  Wait := TEcPhrase.Create(
    EcPPart(rsWait, ecWait),
    EcPPart(rsColon, ecWait),
    EcPPart(rsFrames.Format([Params.Integers[0]]), ecWait)
  );
end;

function TEcStringiser.TintFlashScreen(Params: TJSONArray; FormatString: String
  ): TEcPhrase;
begin
  TintFlashScreen := AddWait(Params, 2,
    SimpleEcPhrase(
      FormatString.Format([
        Params.Arrays[0].Integers[0],
        Params.Arrays[0].Integers[1],
        Params.Arrays[0].Integers[2],
        Params.Arrays[0].Integers[3],
        rsFrames.Format([Params.Integers[1]])
      ]),
      ecScreen
    )
  );
end;

function TEcStringiser.ShakeScreen(Params: TJSONArray): TEcPhrase;
begin
  ShakeScreen := AddWait(Params, 3,
    SimpleEcPhrase(
      rsShakeScreen.Format([
        Params.Integers[0],
        Params.Integers[1],
        rsFrames.Format([Params.Integers[2]])
      ]), ecScreen
    )
  );
end;

function TEcStringiser.SetWeatherEffect(Params: TJSONArray): TEcPhrase;
var
  Text, Time: String;
begin
  Time := rsFrames.Format([Params.Integers[2]]);

  if (Params[0].JSONType = jtString) and (Params.Strings[0] <> 'none') then
    Text := rsSetWeatherEffect_none.Format([Time])
  else
    Text := rsSetWeatherEffect.Format([
         GetWeatherEffectName(Params.Strings[0]),
         Params.Integers[1],
         Time
    ]);


  SetWeatherEffect := AddWait(Params, 3,
    SimpleEcPhrase(Text, ecScreen)
  );
end;

function TEcStringiser.Sound(Params: TJSONArray; CommandName: String;
  Colour: TEcColour): TEcPhrase;
var
  Snd: TJSONObject;
begin
  if (Params.Count >= 1) and (Params[0].JSONType = jtObject) then
    Snd := Params.Objects[0];

  Sound := TEcPhrase.Create(
    EcPPart(CommandName, Colour),
    EcPPart(rsColon, Colour),
    EcPPart(SoundDetails(Snd), Colour)
  );
end;

function TEcStringiser.FadeoutSound(Params: TJSONArray; CommandName: String
  ): TEcPhrase;
begin
  FadeoutSound := TEcPhrase.Create(
    EcPPart(CommandName, ecAudioVideo),
    EcPPart(rsColon, ecAudioVideo),
    EcPPart(rsSeconds.Format([Params.Integers[0]]), ecAudioVideo)
  );
end;

function TEcStringiser.PlayMovie(Params: TJSONArray): TEcPhrase;
begin
  PlayMovie := TEcPhrase.Create(
    EcPPart(rsPlayMovie, ecAudioVideo),
    EcPPart(rsColon, ecAudioVideo),
    EcPPart(FileOrNone(Params.Strings[0]), ecAudioVideo)
  );
end;

function TEcStringiser.BattleProcessing(Params: TJSONArray): TEcPhrase;
  function BattleName: String;
  begin
    case Params.Integers[0] of
      0: BattleName := Db.GetTroopName(Params.Integers[1]);
      1: BattleName := rsIndirectVariable.Format([Db.GetVariableName(Params.Integers[1])]);
      2: BattleName := rsBattleProcessing_asEncounter;
    else
      BattleName := rsUnknownParameter;
    end;
  end;
begin
  BattleProcessing := TEcPhrase.Create(
    EcPPart(rsBattleProcessing, ecScene),
    EcPPart(rsColon, ecScene),
    EcPPart(BattleName, ecScene)
  );
end;

function TEcStringiser.ShopProcessing(Params: TJSONArray;
  IsContinuation: Boolean): TEcPhrase;
var
  NameColour: TEcColour;
  WareName: String;
begin
  if IsContinuation then
    NameColour := ecInvisible
  else
    NameColour := ecScene;

  case Params.Integers[0] of
    0: WareName:= Db.GetItemName(Params.Integers[1], False);
    1: WareName:= Db.GetWeaponName(Params.Integers[1], False);
    2: WareName:= Db.GetArmourName(Params.Integers[1], False);
  end;

  ShopProcessing := TEcPhrase.Create(
    EcPPart(rsShopProcessing, NameColour),
    EcPPart(rsColon, ecScene),
    EcPPart(WareName, ecScene)
  );
end;

function TEcStringiser.NameInputProcessing(Params: TJSONArray): TEcPhrase;
begin
  NameInputProcessing := TEcPhrase.Create(
    EcPPart(rsNameInputProcessing.Format([
      Db.GetActorName(Params.Integers[0], False),
      Params.Integers[1]
    ]), ecScene)
  );
end;

function TEcStringiser.ChangeVehicleBgm(Params: TJSONArray): TEcPhrase;
begin
  ChangeVehicleBgm := SimpleEcPhrase(rsChangeVehicleBgm.Format([
    Vehicle(Params.Integers[0]),
    SoundDetails(Params.Objects[1])
  ]), ecSystem);
end;

function TEcStringiser.ChangeWindowColour(Params: TJSONArray): TEcPhrase;
var
  Colour: TJSONArray;
begin
  Colour := Params.Arrays[0];
  ChangeWindowColour := SimpleEcPhrase(rsChangeWindowColour.Format([
    Colour.Integers[0],
    Colour.Integers[1],
    Colour.Integers[2]
  ]), ecSystem);
end;

function TEcStringiser.ChangeActorImages(Params: TJSONArray): TEcPhrase;
  function WithIndex(Fn: String; Index: Integer): String;
  begin
    if Fn = '' then
      WithIndex := rsNoFile
    else
      WithIndex := rsImageWithIndex.Format([Fn, Index]);
  end;
begin
  ChangeActorImages := TEcPhrase.Create(
    EcPPart(rsChangeActorImages, ecSystem),
    EcPPart(rsColon, ecSystem),
    EcPPart(Db.GetActorName(Params.Integers[0]), ecSystem),
    EcPPart(rsComma, ecSystem),
    EcPPart(WithIndex(Params.Strings[1], Params.Integers[2]), ecSystem),
    EcPPart(rsComma, ecSystem),
    EcPPart(WithIndex(Params.Strings[3], Params.Integers[4]), ecSystem),
    EcPPart(rsComma, ecSystem),
    EcPPart(FileOrNone(Params.Strings[5]), ecSystem)
  );
end;

function TEcStringiser.ChangeVehicleImage(Params: TJSONArray): TEcPhrase;
  function ImageName: String;
  begin
    if Params.Strings[1] = '' then
      ImageName := rsNoFile
    else
      ImageName := rsImageWithIndex.Format([Params.Strings[1], Params.Integers[2]]);
  end;
begin
  ChangeVehicleImage := TEcPhrase.Create(
    EcPPart(rsChangeVehicleImage, ecSystem),
    EcPPart(rsColon, ecSystem),
    EcPPart(Vehicle(Params.Integers[0]), ecSystem),
    EcPPart(rsComma, ecSystem),
    EcPPart(ImageName, ecSystem)
  );
end;

function TEcStringiser.ChangeTileset(Params: TJSONArray): TEcPhrase;
begin
  ChangeTileset := TEcPhrase.Create(
    EcPPart(rsChangeTileset.Format([
      Db.GetTilesetName(Params.Integers[0], False)
    ]), ecMap)
  );
end;

function TEcStringiser.ChangeBattleBack(Params: TJSONArray): TEcPhrase;
  function GetBbName: String;
  var
    Bg1, Bg2: String;
  begin
    Bg1 := Params.Strings[0];
    Bg2 := Params.Strings[0];

    if (Bg1 = '') and (Bg2 = '') then
      GetBbName := rsNoFile
    else
      GetBbName := rsBattleBack.Format([FileOrNone(Bg1), FileOrNone(Bg2)]);
  end;

begin
  ChangeBattleBack := TEcPhrase.Create(
    EcPPart(rsChangeBattleBack.Format([GetBbName]), ecMap)
  );
end;

function TEcStringiser.ChangeParallax(Params: TJSONArray): TEcPhrase;
  function GetFaded: String;
  var
    Comments: String = '';
  begin
    if Params.Booleans[1] then
      Comments := rsChangeParallax_loopHorz;

    if Params.Booleans[1] then begin
      if Comments <> '' then
        Comments := Comments + rsComma;
      Comments := Comments + rsChangeParallax_loopHorz;
    end;

    if Comments = '' then
      GetFaded := ''
    else
      GetFaded := rsOpenBracket + Comments + rsCloseBracket;
  end;
begin
  ChangeParallax := TEcPhrase.Create(
    EcPPart(rsChangeParallax, ecMap),
    EcPPart(rsColon, ecMap),
    EcPPart(FileOrNone(Params.Strings[0]), ecMap),
    EcPPart(rsSpace, ecFaded),
    EcPPart(GetFaded, ecFaded)
  );
end;

function TEcStringiser.GetLocationInfo(Params: TJSONArray): TEcPhrase;
var
  X, Y: String;

  procedure FillXY;
  begin
    if Params.Integers[2] = 0 then begin
      X := IntToStr(Params.Integers[3]);
      Y := IntToStr(Params.Integers[4]);
    end else begin
      X := rsIndirectVariable.Format([Db.GetVariableName(Params.Integers[3])]);
      Y := rsIndirectVariable.Format([Db.GetVariableName(Params.Integers[4])]);
    end;
  end;

  function GetLocationType: String;
  begin
    case Params.Integers[1] of
      0: GetLocationType := rsGetLocationInfo_terrainTag;
      1: GetLocationType := rsGetLocationInfo_eventId;
      2 .. 5: GetLocationType := rsGetLocationInfo_tileId.Format([Params.Integers[1] - 1]);
    else
      GetLocationType := rsGetLocationInfo_regionId;
    end;
  end;

begin
  FillXY;

  GetLocationInfo := SimpleEcPhrase(
    rsGetLocationInfo.Format([
      Db.GetVariableName(Params.Integers[0]),
      GetLocationType,
      X, Y
    ]),
    ecMap
  );
end;

function TEcStringiser.ChangeEnemyHpMpTp(Params: TJSONArray; EcName,
  PointName: String; HasKnockout: Boolean): TEcPhrase;
  function GetValue: String;
  begin
    case Params.Integers[2] of
      0: GetValue := rsPoints.Format([Params.Integers[3], PointName]);
      1: GetValue := rsIndirectVariable.Format([Db.GetVariableName(Params.Integers[3])]);
    else
      GetValue := rsUnknownParameter;
    end;
  end;

  function GetAction: String;
  begin
    case Params.Integers[1] of
      0: Result := rsChangeHpMpTp_add.Format([TroopMemberName(Params.Integers[0]), GetValue]);
      1: Result := rsChangeHpMpTp_remove.Format([TroopMemberName(Params.Integers[0]), GetValue]);
    else
      Result := rsUnknownParameter;
    end;

  end;

var
  Phrase: TEcPhrase;
begin
  Phrase := TEcPhrase.Create(
    EcPPart(ecName, ecBattle),
    EcPPart(rsColon, ecBattle),
    EcPPart(GetAction, ecBattle)
  );

  if HasKnockout then
    ChangeEnemyHpMpTp := ChangeHp_AddAllowKnockout(Phrase, Params)
  else
    ChangeEnemyHpMpTp := Phrase
end;

function TEcStringiser.ChangeEnemyState(Params: TJSONArray): TEcPhrase;
  function GetAction: String;
  var
    EnemyName, StateName: String;
  begin
    EnemyName := TroopMemberName(Params.Integers[0]);
    StateName := Db.GetStateName(Params.Integers[2]);

    case Params.Integers[1] of
      0: Result := rsChangeState_add.Format([EnemyName, StateName]);
      1: Result := rsChangeState_remove.Format([EnemyName, StateName]);
    else
      Result := rsUnknownParameter;
    end;
  end;
begin
  ChangeEnemyState := TEcPhrase.Create(
    EcPPart(rsChangeEnemyState, ecBattle),
    EcPPart(rsColon, ecBattle),
    EcPPart(GetAction, ecBattle)
  );
end;

function TEcStringiser.EnemyCompleteRecoveryAppear(Params: TJSONArray;
  CommandName: String): TEcPhrase;
var
  Target: String;
begin
  Target := TroopMemberName(Params.Integers[0]);
  EnemyCompleteRecoveryAppear := TEcPhrase.Create(
    EcPPart(CommandName, ecBattle),
    EcPPart(rsColon, ecBattle),
    EcPPart(Target, ecBattle)
  );
end;

function TEcStringiser.EnemyTranform(Params: TJSONArray): TEcPhrase;
var
  Target: String;
  NewEnemy: String;
begin
  Target := TroopMemberName(Params.Integers[0]);
  NewEnemy := Db.GetEnemyName(Params.Integers[1], False);

  EnemyTranform := SimpleEcPhrase(
    rsEnemyTransform.Format([
      Target, NewEnemy
    ]),
    ecBattle
  );
end;

function TEcStringiser.ShowBattleAnimation(Params: TJSONArray): TEcPhrase;
var
  Target, AnimName: String;
begin
  if Params.Booleans[2] then
    Target := rsWholeTroop
  else
    Target := TroopMemberName(Params.Integers[0]);

  AnimName := Db.GetAnimName(Params.Integers[1], False);

  ShowBattleAnimation := SimpleEcPhrase(
    rsShowBattleAnimation.Format([Target, AnimName]),
    ecBattle
  );
end;

function TEcStringiser.ForceAction(Params: TJSONArray): TEcPhrase;
  function GetSubject: String;
  begin
    case Params.Integers[0] of
      0: GetSubject := TroopMemberName(Params.Integers[1]);
      1: GetSubject := Db.GetActorName(Params.Integers[1], False);
    else
      GetSubject := rsUnknownParameter;
    end;
  end;

  function GetTarget: String;
  begin
    case Params.Integers[3] of
      -2: GetTarget := rsForceAction_lastTarget;
      -1: GetTarget := rsForceAction_randomTarget;
    else
      GetTarget := rsNumber.Format([Params.Integers[3]]);
    end;
  end;

begin
  ForceAction := SimpleEcPhrase(
    rsForceAction.Format([
      GetSubject,
      Db.GetSkillName(Params.Integers[2]),
      GetTarget
    ]),
    ecBattle
  );
end;

function TEcStringiser.Script(Params: TJSONArray): TEcPhrase;
begin
  Script := TEcPhrase.Create(
    EcPPart(rsScript, ecAdvanced),
    EcPPart(rsColon, ecAdvanced),
    EcPPart(Params.Strings[0], ecCode)
  );
end;

function TEcStringiser.ScriptLine(Params: TJSONArray): TEcPhrase;
begin
  ScriptLine := TEcPhrase.Create(
    EcPPart(rsScript, ecInvisible),
    EcPPart(rsColon, ecAdvanced),
    EcPPart(Params.Strings[0], ecCode)
  );
end;

function TEcStringiser.PluginCommand(Params: TJSONArray): TEcPhrase;
begin
  PluginCommand := TEcPhrase.Create(
    EcPPart(rsPluginCommand, ecAdvanced),
    EcPPart(rsColon, ecAdvanced),
    EcPPart(Params.Strings[0], ecString)
  );
end;

function TEcStringiser.StringiseEc(Command: TJSONObject): TEcPhrase;
var
  Code: Integer = 0;
  CodeJson: TJSONNumber;
  Params: TJSONArray = nil;
begin
  if (Command <> nil) and Command.Find('code', CodeJson) then
    Code := CodeJson.AsInteger;
  if (Command <> nil) then
    Command.Find('parameters', Params);

  case Code of
    0: StringiseEc := SimpleEcPhrase('', ecInvisible);

    { Page 1 }
    SHOW_MESSAGE_START_EC_CODE: StringiseEc := ShowMessageStart(Params);
    SHOW_MESSAGE_LINE_EC_CODE:  StringiseEc := ShowMessageLine(Params);
    SHOW_CHOICES_START_EC_CODE: StringiseEc := ShowChoicesStart(Params);
    SHOW_CHOICES_BRANCH_EC_CODE: StringiseEc := ShowChoicesBranch(Params);
    SHOW_CHOICES_CANCEL_BRANCH_EC_CODE: StringiseEc := SimpleEcPhrase(rsShowChoicesCancelBranchEc, ecMessage);
    SHOW_CHOICES_END_EC_CODE: StringiseEc := SimpleEcPhrase(rsShowChoicesEndEc, ecMessage);
    INPUT_NUMBER_EC_CODE: StringiseEc := InputNumber(Params);
    SELECT_ITEM_EC_CODE: StringiseEc := SelectItem(Params);
    SCROLLING_TEXT_START_EC_CODE: StringiseEc := ScrollingTextStart(Params);
    SCROLLING_TEXT_LINE_EC_CODE: StringiseEc := ScrollingTextLine(Params);

    SET_SWITCHES_EC_CODE: StringiseEc := SetSwitches(Params);
    SET_VARIABLES_EC_CODE: StringiseEc := SetVariables(Params);
    SET_SELF_SWITCH_EC_CODE: StringiseEc := SetSelfSwitch(Params);
    CONTROL_TIMER_EC_CODE: StringiseEc := ControlTimer(Params);
    CONDITIONAL_BRANCH_IF_EC_CODE: StringiseEc := ConditionalBranch(Params);
    CONDITIONAL_BRANCH_ELSE_EC_CODE: StringiseEc := SimpleEcPhrase(rsConditionalBranch_else, ecFlow);
    CONDITIONAL_BRANCH_END_EC_CODE: StringiseEc := SimpleEcPhrase(rsConditionalBranch_end, ecFlow);

    LOOP_EC_CODE: StringiseEc := SimpleEcPhrase(rsLoop, ecFlow);
    LOOP_END_EC_CODE: StringiseEc := SimpleEcPhrase(rsLoop_end, ecFlow);
    BREAK_LOOP_EC_CODE: StringiseEc := SimpleEcPhrase(rsBreakLook, ecFlow);
    EXIT_EVENT_PROCESSING_EC_CODE: StringiseEc := SimpleEcPhrase(rsExitEventProcessing, ecFlow);

    LABEL_EC_CODE: StringiseEc := LabelEc(Params);
    GOTO_EC_CODE: StringiseEc := GotoEc(Params);
    COMMON_EVENT_EC_CODE: StringiseEc := CallCommonEvent(Params);
    COMMENT_EC_CODE: StringiseEc := Comment(Params);
    COMMENT_CONTINUATION_EC_CODE: StringiseEc := CommentContinuation(Params);

    CHANGE_GOLD_EC_CODE: StringiseEc := ChangeGold(Params);
    CHANGE_ITEMS_EC_CODE: StringiseEc := ChangeItems(Params);
    CHANGE_WEAPONS_EC_CODE: StringiseEc := ChangeWeapons(Params);
    CHANGE_ARMOURS_EC_CODE: StringiseEc := ChangeArmours(Params);
    CHANGE_PARTY_MEMBER_EC_CODE: StringiseEc := ChangeParty(Params);

    CHANGE_ACTOR_HP_EC_CODE: StringiseEc := ChangeHpMpTp(Params, rsChangeHp, Db.System.Objects['terms'].Arrays['basic'].Strings[2], True);
    CHANGE_ACTOR_MP_EC_CODE: StringiseEc := ChangeHpMpTp(Params, rsChangeMp, Db.System.Objects['terms'].Arrays['basic'].Strings[4], False);
    CHANGE_ACTOR_TP_EC_CODE: StringiseEc := ChangeHpMpTp(Params, rsChangeTp, Db.System.Objects['terms'].Arrays['basic'].Strings[6], False);
    CHANGE_ACTOR_STATE_EC_CODE: StringiseEc := ChangeState(Params);
    COMPLETE_ACTOR_RECOVER_EC_CODE: StringiseEc := CompleteRecovery(Params);
    CHANGE_EXPERIENCE_EC_CODE: StringiseEc := ChangeExpLevel(Params, False);
    CHANGE_LEVEL_EC_CODE: StringiseEc := ChangeExpLevel(Params, True);
    CHANGE_PARAM_EC_CODE: StringiseEc := ChangeParam(Params);
    CHANGE_SKILL_EC_CODE: StringiseEc := ChangeSkill(Params);
    CHANGE_EQUIPMENT_EC_CODE: StringiseEc := ChangeEquipment(Params);
    CHANGE_NAME_EC_CODE: StringiseEc := ChangeName(Params);
    CHANGE_CLASS_EC_CODE: StringiseEc := ChangeClass(Params);
    CHANGE_NICKNAME_EC_CODE: StringiseEc := ChangeNickname(Params);
    CHANGE_PROFILE_EC_CODE: StringiseEc := ChangeProfile(Params);

    { Page 2 }
    TRANSFER_PLAYER_EC_CODE: StringiseEc := TransferPlayer(Params);
    SET_VEHICLE_LOCATION_EC_CODE: StringiseEc := SetVehicleLocation(Params);
    SET_EVENT_LOCATION_EC_CODE: StringiseEc := SetEventLocation(Params);
    SCROLL_MAP_EC_CODE: StringiseEc := ScrollMap(Params);
    SET_MOVEMENT_ROUTE_EC_CODE: StringiseEc := SetMoveRoute(Params);
    SET_MOVEMENT_ROUTE_SUBCOMMAND_EC_CODE: StringiseEc := SetMoveRouteLine(Params);
    GET_ON_OFF_VEHICLE_EC_CODE: StringiseEc := SimpleEcPhrase(rsGetOnOffVehicle, ecMove);

    CHANGE_PLAYER_VISIBILITY_EC_CODE: StringiseEc := OnOffCommand(Params, rsChangePlayerVisibility_on, rsChangePlayerVisibility_off, ecChar);
    CHANGE_PLAYER_FOLLOWERS_EC_CODE: StringiseEc := OnOffCommand(Params, rsChangePlayerFollowers_on, rsChangePlayerFollowers_off, ecChar);
    GATHER_FOLLOWERS_EC_CODE: StringiseEc := SimpleEcPhrase(rsGatherFollowers, ecChar);
    SHOW_ANIMATION_EC_CODE: StringiseEc := ShowAnimation(Params);
    SHOW_BALLOON_ICON_EC_CODE: StringiseEc := ShowEmotionBalloon(Params);
    ERASE_EVENT_EC_CODE: StringiseEc := SimpleEcPhrase(rsEraseEvent, ecChar);

    SHOW_PICTURE_EC_CODE: StringiseEc := ShowPicture(Params);
    MOVE_PICTURE_EC_CODE: StringiseEc := MovePicture(Params);
    ROTATE_PICTURE_EC_CODE: StringiseEc := RotatePicture(Params);
    TINT_PICTURE_EC_CODE: StringiseEc := TintPicture(Params);
    ERASE_PICTURE_EC_CODE: StringiseEc := ErasePicture(Params);

    WAIT_EC_CODE: StringiseEc := Wait(Params);
    FADEOUT_SCREEN_EC_CODE: StringiseEc := SimpleEcPhrase(rsFadeoutScreen, ecScreen);
    FADEIN_SCREEN_EC_CODE: StringiseEc := SimpleEcPhrase(rsFadeinScreen, ecScreen);
    TINT_SCREEN_EC_CODE: StringiseEc := TintFlashScreen(Params, rsTintScreen);
    FLASH_SCREEN_EC_CODE: StringiseEc := TintFlashScreen(Params, rsFlashScreen);
    SHAKE_SCREEN_EC_CODE: StringiseEc := ShakeScreen(Params);
    SET_WEATHER_EFFECT_EC_CODE: StringiseEc := SetWeatherEffect(Params);

    PLAY_BGM_EC_CODE: StringiseEc := Sound(Params, rsPlayBgm, ecAudioVideo);
    FADEOUT_BGM_EC_CODE: StringiseEc := FadeoutSound(Params, rsFadeoutBgm);
    SAVE_BGM_EC_CODE: StringiseEc := SimpleEcPhrase(rsSaveBgm, ecAudioVideo);
    REPLAY_BGM_EC_CODE: StringiseEc := SimpleEcPhrase(rsReplayBgm, ecAudioVideo);
    PLAY_BGS_EC_CODE: StringiseEc := Sound(Params, rsPlayBgs, ecAudioVideo);
    FADEOUT_BGS_EC_CODE: StringiseEc := FadeoutSound(Params, rsFadeoutBgs);
    PLAY_ME_EC_CODE: StringiseEc := Sound(Params, rsPlayMe, ecAudioVideo);
    PLAY_SE_EC_CODE: StringiseEc := Sound(Params, rsPlaySe, ecAudioVideo);
    STOP_SE_EC_CODE: StringiseEc := SimpleEcPhrase(rsStopSe, ecAudioVideo);
    PLAY_MOVIE_EC_CODE: StringiseEc := PlayMovie(Params);

    { Page 3 }
    BATTLE_PROCESSING_EC_CODE: StringiseEc := BattleProcessing(Params);
    BATTLE_PROCESSING_WIN_EC_CODE: StringiseEc := SimpleEcPhrase(rsBattleProcessing_win, ecScene);
    BATTLE_PROCESSING_ESCAPE_EC_CODE: StringiseEc := SimpleEcPhrase(rsBattleProcessing_escape, ecScene);
    BATTLE_PROCESSING_LOSE_EC_CODE: StringiseEc := SimpleEcPhrase(rsBattleProcessing_lose, ecScene);
    BATTLE_PROCESSING_END_EC_CODE: StringiseEc := SimpleEcPhrase(rsBattleProcessing_end, ecScene);
    SHOP_PROCESSING_EC_CODE: StringiseEc := ShopProcessing(Params, False);
    SHOP_PROCESSING_LINE_EC_CODE: StringiseEc := ShopProcessing(Params, True);
    NAME_INPUT_PROCESSING_EC_CODE: StringiseEc := NameInputProcessing(Params);
    OPEN_MENU_SCREEN_EC_CODE: StringiseEc := SimpleEcPhrase(rsOpenMenuScreen, ecScene);
    OPEN_SAVE_SCREEN_EC_CODE: StringiseEc := SimpleEcPhrase(rsOpenSaveScreen, ecScene);
    GAME_OVER_EC_CODE: StringiseEc := SimpleEcPhrase(rsGameOver, ecScene);
    RETURN_TO_TITLE_SCREEN_EC_CODE: StringiseEc := SimpleEcPhrase(rsReturnToTitleScreen, ecScene);

    CHANGE_BATTLE_BGM_EC_CODE: StringiseEc := Sound(Params, rsChangeBattleBgm, ecSystem);
    CHANGE_VICTORY_ME_EC_CODE: StringiseEc := Sound(Params, rsChangeVictoryMe, ecSystem);
    CHANGE_DEFEAT_ME_EC_CODE: StringiseEc := Sound(Params, rsChangeDefeatMe, ecSystem);

    CHANGE_VEHICLE_BGM_EC_CODE: StringiseEc := ChangeVehicleBgm(Params);
    CHANGE_SAVE_ACCESS_EC_CODE: StringiseEc := OnOffCommand(Params, rsChangeSaveAccess_on, rsChangeSaveAccess_off, ecSystem);
    CHANGE_MENU_ACCESS_EC_CODE: StringiseEc := OnOffCommand(Params, rsChangeMenuAccess_on, rsChangeMenuAccess_off, ecSystem);
    CHANGE_ENCOUNTER_EC_CODE: StringiseEc := OnOffCommand(Params, rsChangeEncounter_on, rsChangeEncounter_off, ecSystem);
    CHANGE_FORMATION_ACCESS_EC_CODE: StringiseEc := OnOffCommand(Params, rsChangeFormationAccess_on, rsChangeFormationAccess_off, ecSystem);
    CHANGE_WINDOW_COLOUR_EC_CODE: StringiseEc := ChangeWindowColour(Params);
    CHANGE_ACTOR_IMAGES_EC_CODE: StringiseEc := ChangeActorImages(Params);
    CHANGE_VEHICLE_IMAGE_EC_CODE: StringiseEc := ChangeVehicleImage(Params);

    CHANGE_MAP_NAME_DISPLAY_EC_CODE: StringiseEc := OnOffCommand(Params, rsChangeMapNameDisplay_on, rsChangeMapNameDisplay_on, ecMap);
    CHANGE_TILESET_EC_CODE: StringiseEc := ChangeTileset(Params);
    CHANGE_BATTLEBACK_EC_CODE: StringiseEc := ChangeBattleBack(Params);
    CHANGE_PARALLAX_EC_CODE: StringiseEc := ChangeParallax(Params);
    GET_LOCATION_INFO_EC_CODE: StringiseEc := GetLocationInfo(Params);
    CHANGE_ENEMY_HP_EC_CODE: StringiseEc := ChangeEnemyHpMpTp(Params, rsChangeEnemyHp, Db.System.Objects['terms'].Arrays['basic'].Strings[2], True);
    CHANGE_ENEMY_MP_EC_CODE: StringiseEc := ChangeEnemyHpMpTp(Params, rsChangeEnemyMp, Db.System.Objects['terms'].Arrays['basic'].Strings[4], False);
    CHANGE_ENEMY_TP_EC_CODE: StringiseEc := ChangeEnemyHpMpTp(Params, rsChangeEnemyTp, Db.System.Objects['terms'].Arrays['basic'].Strings[6], False);
    CHANGE_ENEMY_STATE_EC_CODE: StringiseEc := ChangeEnemyState(Params);
    COMPLETE_ENEMY_RECOVERY_EC_CODE: StringiseEc := EnemyCompleteRecoveryAppear(Params, rsCompleteEnemyRecovery);
    ENEMY_APPEAR_EC_CODE: StringiseEc := EnemyCompleteRecoveryAppear(Params, rsEnemyAppear);
    ENEMY_TRANSFORM_EC_CODE: StringiseEc := EnemyTranform(Params);
    SHOW_BATTLE_ANIMATION_EC_CODE: StringiseEc := ShowBattleAnimation(Params);
    FORCE_ACTION_EC_CODE: StringiseEc := ForceAction(Params);
    ABORT_BATTLE_EC_CODE: StringiseEc := SimpleEcPhrase(rsAbortBattle, ecBattle);

    SCRIPT_EC_CODE: StringiseEc := Script(Params);
    SCRIPT_LINE_EC_CODE: StringiseEc := ScriptLine(Params);
    PLUGIN_COMMAND_EC_CODE: StringiseEc := PluginCommand(Params);
  else
    StringiseEc := Unknown(Code);
  end;

end;

function SimpleEcPhrase(Text: String; Colour: TEcColour): TEcPhrase;
begin
  SimpleEcPhrase := TEcPhrase.Create(
    EcPPart(Text, Colour)
  );
end;

function EcIsContinuation(Code: Integer): Boolean;
begin
  EcIsContinuation := Code >= 400;
end;

end.

